package cn.quang.utils.decorator;

import cn.quang.utils.decorator.scene.*;
import lombok.extern.slf4j.Slf4j;

/**
 * 装饰器执行器
 * 用于简化Try-Catch-Throw模式，通过lambda表达式简化代码编写
 * 同时，对于异常场景，提供异常回调，且异常内部可决定是否返回默认值
 */
@Slf4j
public class TryCatchExecutor {


    /**
     * 异常装饰器执行方法
     * 需提供两个执行类，非异常场景执行runner，异常场景执行callback
     * @param sceneName 场景名
     * @param thrower 业务逻辑执行器
     * @param callback 异常回调
     */
    public static <T> T execute(String sceneName, IExceptionThrower<T> thrower, IExceptionCallback<T> callback){
        return execute(sceneName, true, thrower, callback);
    }

    /**
     * 异常装饰器执行方法
     * 需提供两个执行类，非异常场景执行runner，异常场景执行callback
     * @param sceneName 场景名
     * @param isLogger 是否需要打印异常详情
     * @param thrower 业务逻辑执行器
     * @param callback 异常回调
     */
    public static <T> T execute(String sceneName, boolean isLogger, IExceptionThrower<T> thrower, IExceptionCallback<T> callback){
        try {
            return thrower.run();
        } catch (Exception e) {
            if(isLogger){
                log.error(String.format("[Decorator]scene[%s]throws exception: ", sceneName), e);
            }
            return callback.callback(e);
        }
    }

    /**
     * 条件分支装饰器执行方法
     * @param sceneName 场景名
     * @param decider 业务逻辑执行器
     * @param trueCallback true回调
     * @param falseCallback false回调
     * @param exceptionCallback 异常回调
     */
    public static <T> T execute(String sceneName, IConditionDecider decider, IConditionDecideCallback<T> trueCallback, IConditionDecideCallback<T> falseCallback, IExceptionCallback<T> exceptionCallback){
        return execute(sceneName, true, decider, trueCallback, falseCallback, exceptionCallback);
    }

    /**
     * 条件分支装饰器执行方法
     * @param sceneName 场景名
     * @param isLogger 是否打印日志
     * @param decider 业务逻辑执行器
     * @param trueCallback true回调
     * @param falseCallback false回调
     * @param exceptionCallback 异常回调
     */
    public static <T> T execute(String sceneName, boolean isLogger, IConditionDecider decider, IConditionDecideCallback<T> trueCallback, IConditionDecideCallback<T> falseCallback, IExceptionCallback<T> exceptionCallback){
        try{
            boolean decideResult = decider.decide();
            log.info(String.format("[Decorator]condition scene[%s] hit result：%s", sceneName, decideResult));
            if(decideResult){
                return trueCallback.callback();
            }
            return falseCallback.callback();
        }catch (Exception e){
            if(isLogger){
                log.error(String.format("[Decorator]condition scene[%s]throws exception: ", sceneName), e);
            }
            return exceptionCallback.callback(e);
        }
    }

    /**
     * 异常装饰器执行方法(无返回值)
     * 需提供两个执行类，非异常场景执行runner，异常场景执行callback
     * @param sceneName 场景名
     * @param isLogger 是否需要打印异常详情
     * @param thrower 业务逻辑执行器
     * @param callback 异常回调
     */
    public static void executeWithNoneResult(String sceneName, boolean isLogger, IExceptionNoneResultThrower thrower, IExceptionNoneResultCallback callback){
        try {
            thrower.run();
        } catch (Exception e) {
            if(isLogger){
                log.error(String.format("[Decorator]scene[%s]throws exception: ", sceneName), e);
            }
            callback.callback(e);
        }
    }

    /**
     * 异常装饰器执行方法(无返回值)
     * 需提供两个执行类，非异常场景执行runner，异常场景执行callback
     * @param sceneName 场景名
     * @param thrower 业务逻辑执行器
     * @param callback 异常回调
     */
    public static void executeWithNoneResult(String sceneName, IExceptionNoneResultThrower thrower, IExceptionNoneResultCallback callback){
        executeWithNoneResult(sceneName, true, thrower, callback);
    }

    /**
     * 异常装饰器执行方法(无返回值)
     * 需提供两个执行类，非异常场景执行runner，异常场景执行callback
     * 同时，该异常仍然会抛出给执行端
     * @param sceneName 场景名
     * @param thrower 业务逻辑执行器
     * @param callback 异常回调
     */
    public static void executeWithNoneResultRethrowException(String sceneName, IExceptionNoneResultThrower thrower, IExceptionNoneResultCallback callback) throws Exception {
        executeWithNoneResultRethrowException(sceneName, true, thrower, callback);
    }

    /**
     * 异常装饰器执行方法(无返回值)
     * 需提供两个执行类，非异常场景执行runner，异常场景执行callback
     * 同时，该异常仍然会抛出给执行端
     * @param sceneName 场景名
     * @param isLogger 是否需要打印异常详情
     * @param thrower 业务逻辑执行器
     * @param callback 异常回调
     */
    public static void executeWithNoneResultRethrowException(String sceneName, boolean isLogger, IExceptionNoneResultThrower thrower, IExceptionNoneResultCallback callback) throws Exception {
        try {
            thrower.run();
        } catch (Exception e) {
            if(isLogger){
                log.error(String.format("[Decorator]scene[%s]throws exception: ", sceneName), e);
            }
            callback.callback(e);
            throw e;
        }
    }

}
